<?php
/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link http://www.workerman.net/
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */

/**
 * 用于检测业务代码死循环或者长时间阻塞等问题
 * 如果发现业务卡死，可以将下面declare打开（去掉//注释），并执行php start.php reload
 * 然后观察一段时间workerman.log看是否有process_timeout异常
 */
//declare(ticks=1);

/**
 * 聊天主逻辑
 * 主要是处理 onMessage onClose
 */

use \GatewayWorker\Lib\Gateway;
use Workerman\Worker;

use App\Models\OftenUsedWords;
use App\Models\KfDialog;
use App\Models\KfMessage;
use App\Models\Admin;
use App\Models\Book;
use App\Models\CpsAdmin;
use App\Models\BookList;
use App\Models\Activity;

class Events
{
    protected static $type;

    public static function onWorkerStart($worker)
    {
        Cache::initClient();
        DB::initEloquent();
        Message::loadBadWords();
        // 开启一个内部端口，方便内部系统推送数据，Text协议格式 文本+换行符
        $inner_text_worker = new Worker('Text://0.0.0.0:5678');
        $inner_text_worker->reusePort = true;
        $inner_text_worker->onMessage = function ($connection, $buffer) use ($worker) {
            $data = json_decode($buffer, true);

            Dialog::handle($data);

            $connection->send($data ? 'ok' : 'fail');
        };
        $inner_text_worker->listen();
        // \Workerman\Lib\Timer::add(1, function () {
        //     print_r('定时器：：：：：：：：：：：');
        // });
        \Workerman\Lib\Timer::add(10, function () {
            Cache::checkExpire();
        });
    }

    // 针对uid推送数据
    function sendMessageByUid($uid, $message)
    {
        global $worker;
        if (isset($worker->uidConnections[$uid])) {
            $connection = $worker->uidConnections[$uid];
            $connection->send($message);
            return true;
        }
        return false;
    }

    /**
     * 有消息时
     * @param int $client_id
     * @param mixed $message
     */
    public static function onMessage($client_id, $message)
    {
        // debug
        echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id session:" . json_encode($_SESSION) . " onMessage:" . $message . "\n";


        // 客户端传递的是json数据
        $message_data = json_decode($message, true);
        if (!$message_data || !isset($message_data['type'])) {
            return;
        }
        self::$type = $type = $message_data['type'];
        // 根据类型执行不同的业务
        switch ($type) {
            // 客户端回应服务端的心跳
            case 'pong':
                return;

            // 待接入列表
            case 'waiting':
                $data = Cache::getWaitingDialogs();
                // print_r($data);
                Gateway::sendToCurrentClient(self::defaultResponse('', $data));
                return;

            // 接入列表
            case 'joined':
                $data = Cache::getJoined($_SESSION['server_id']);
                Gateway::sendToCurrentClient(self::defaultResponse('', $data));
                return;

            // 常用语列表
            case 'word_list':
                $server_id = $_SESSION['server_id'];
                $platform = $_SESSION['platform'];
                $words = OftenUsedWords::where('server_id', $server_id)->where('platform', $platform)->get();
                Gateway::sendToCurrentClient(self::defaultResponse('', $words));
                return;

            // 常用语添加
            case 'word_add':
                $content = $message_data['content'];
                if ($content == '') {
                    Gateway::sendToCurrentClient(self::defaultResponse('内容不能为空', [], 0));
                }
                OftenUsedWords::create(['server_id' => $_SESSION['server_id'], 'platform' => $_SESSION['platform'], 'content' => $content]);
                Gateway::sendToCurrentClient(self::defaultResponse());
                return;

            // 常用语删除
            case 'word_del':
                if (!isset($message_data['id'])) {
                    Gateway::sendToCurrentClient(self::defaultResponse('内容ID不能为空'));
                }
                $words = OftenUsedWords::find($message_data['id']);
                if (is_null($words) || $words['server_id'] != $_SESSION['server_id']) {
                    Gateway::sendToCurrentClient(self::defaultResponse('常用语不存在'));
                }
                $words->delete();
                Gateway::sendToCurrentClient(self::defaultResponse());
                return;

            // 书籍查找
            case 'book_search':
                $name = $message_data['name'];
                $user = Cache::getDialogByUserId($message_data['user_id']);
                if (!$user) {
                    Gateway::sendToCurrentClient(self::defaultResponse());
                }
                $cpsadmin = CpsAdmin::find($user['admin_id']);
                if (!$cpsadmin || is_null($cpsadmin)) {
                    return Gateway::sendToCurrentClient(self::defaultResponse());
                }
                $bookQuery = Book::query()->where('status', 0)->where('is_ground', 1);
                if (0 == $cpsadmin->is_special) {
                    $bookQuery->where('is_hot', 0);
                }
                $books = $bookQuery->where('name', 'like', '%' . $name . '%')
                    ->orWhere('book_id', $name)
                    ->get(['id', 'name', 'book_id']);
                Gateway::sendToCurrentClient(self::defaultResponse('', $books));
                return;

            // 已处理列表
            case 'finished':
                // $dialogs = KfDialog::get();

                $dialogs = KfDialog::where('server_id', $_SESSION['server_id'])->where('platform', $_SESSION['platform'])->whereStatus('finished')->orderByDesc('updated_at')->get();
                Gateway::sendToCurrentClient(self::defaultResponse('', $dialogs));
                return;

            // 已处理详情
            case 'finished_info':
                $messages = KfMessage::where('dialog_id', $message_data['id'])->oldest()->get();
                $dialog = KfDialog::select('id', 'updated_at')->where('id', $message_data['id'])->first();
                Gateway::sendToCurrentClient(json_encode(array('type' => $type, 'message' => 'ok', 'code' => 200, 'data' => $messages, 'endtime' => $dialog)));
                return;

            // 会话详情
            case 'joined_info':
                if (Cache::isUserBanned($message_data['user_id'])) {
                    Gateway::sendToCurrentClient(self::defaultResponse('该用户已被禁言！', [], 0));
                }
                $dialog = Cache::getDialogAndResetUnread($message_data['user_id']);
                Cache::setServerLastUser($dialog['server_id'], $message_data['user_id']);
                Gateway::sendToCurrentClient(self::defaultResponse('', $dialog));
                return;

            // 单个接入
            case 'single_join':
                $dialog = Cache::getDialogByUserId($message_data['user_id']);
                if (!$dialog) {
                    Gateway::sendToCurrentClient(self::defaultResponse('该会话已过期', [], 0));
                }
                Cache::setAddOpened($message_data['user_id'], $_SESSION['server_id']);
                KfDialog::where('id', $dialog['dialog_id'])->update(['server_id' => $_SESSION['server_id']]);
                Gateway::sendToCurrentClient(self::defaultResponse());
                self::$type = 'waiting';
                Gateway::sendToAll(self::defaultResponse('', Cache::getWaitingDialogs()));
                return;

            // 全部接入
            case 'all_join':
                Dialog::addOpenedForWechat($message_data['wechat_id'], $_SESSION['server_id']);
                Gateway::sendToCurrentClient(self::defaultResponse());
                self::$type = 'waiting';
                Gateway::sendToAll(self::defaultResponse('', Cache::getWaitingDialogs()));
                return;

            case 'login':
                // 把用户信息放到session中
                $server_id = $message_data['server_id'];

                // if(is_null($admin))
                // {
                //     return Gateway::sendToCurrentClient(json_encode(array('type' => $type, 'message' => '用户不存在', 'code' => 404)));
                // }

                // if(is_null($admin) || !password_verify($password, $admin->password))
                // {
                //     Gateway::sendToCurrentClient(self::response($type, $_SESSION));
                // }

                $admin = Admin::find($server_id);

                $serverInfo = Cache::getServer($server_id);
                if (!empty($serverInfo)) {
                    $_SESSION = $serverInfo;
                    $client_ids = Gateway::getClientIdByUid($server_id);
                    foreach ($client_ids as $clientid) {
                        Gateway::unbindUid($clientid, $server_id);
                        if ($client_id != $clientid) {
                            Gateway::sendToClient($clientid, json_encode(['type' => 'exit']));
                        }
                    }
                    Gateway::bindUid($client_id, $_SESSION['server_id']);
                    Gateway::sendToCurrentClient(self::defaultResponse('', $_SESSION));
                    return;
                }

                $_SESSION['server_id'] = $server_id;
                $_SESSION['server_name'] = $admin->name;
                $_SESSION['status'] = 'online';
                $_SESSION['platform'] = 'system';
                $_SESSION['rest_start'] = 0;

                Cache::setServer($_SESSION['server_id'], $_SESSION);

                Gateway::bindUid($client_id, $_SESSION['server_id']);

                Gateway::sendToCurrentClient(self::defaultResponse('', $_SESSION));
                return;

            case 'status':
                $_SESSION['status'] = $message_data['status'];
                if ($message_data['status'] == 'rest') {
                    $_SESSION['rest_start'] = time();
                } else if ($message_data['status'] == 'online') {
                    $_SESSION['rest_start'] = 0;
                }
                Cache::setServerStatus($_SESSION['server_id'], ['status' => $_SESSION['status'], 'rest_start' => $_SESSION['rest_start']]);
                Gateway::sendToCurrentClient(self::defaultResponse('', $_SESSION));
                return;

            // 客户端发言 message: {type:say, to_client_id:xx, content:xx}
            case 'say':
                $content = $message_data['content'];
                $user_id = $message_data['user_id'];
                Message::disableWordExists($content, true);
                $dialog = Cache::getDialogByUserId($user_id);
                if (!$dialog) {
                    return;
                }
                $kf_message = [
                    'dialog_id' => $dialog['dialog_id'],
                    'role' => 'server',
                    'content' => $message_data['content'],
                ];
                KfMessage::create($kf_message);
                Cache::setServerMessage($message_data['user_id'], array_merge($message_data, ['is_auto' => 0]));
                Gateway::sendToCurrentClient(self::defaultResponse());
                $user = Cache::getDialogByUserId($user_id);
                if (isset($user['source']) && $user['source'] == 'hk') {
                    $msgApiUrl = config('MESSAGE_API_URL_HK');
                } else {
                    $msgApiUrl = config('MESSAGE_API_URL');
                }
                Message::sendToUser($msgApiUrl, [
                    'user_id' => $dialog['user_id'],
                    'message' => $content,
                ]);
                return;

            case 'close':
                $dialog = Cache::getDialogByUserId($message_data['user_id']);
                Cache::close($message_data['user_id']);
                KfDialog::where('id', $dialog['dialog_id'])->update(['status' => 'finished']);
                Gateway::sendToCurrentClient(self::defaultResponse());
                return;

            case 'history':
                $dialog_ids = KfDialog::where('user_id', $message_data['user_id'])->pluck('id');
                $messages = KfMessage::whereIn('dialog_id', $dialog_ids)->oldest()->get();
                Gateway::sendToCurrentClient(self::defaultResponse('', $messages));
                return;

            // 书单列表
            case 'book_list':
                $server_id = $_SESSION['server_id'];
                $platform = $_SESSION['platform'];
                $lists = BookList::where('server_id', $server_id)->where('platform', $platform)->get();
                Gateway::sendToCurrentClient(self::defaultResponse('', $lists));
                return;

            // 书单添加
            case 'book_list_add':
                BookList::create([
                    'server_id' => $_SESSION['server_id'],
                    'platform' => $_SESSION['platform'],
                    'name' => $message_data['name'],
                    'header_text' => $message_data['header_text'] ?: '',
                    'list' => $message_data['list'],
                    'footer_text' => $message_data['footer_text'] ?: '',
                    'redirect_to' => $message_data['redirect_to'],
                ]);
                Gateway::sendToCurrentClient(self::defaultResponse());
                return;

            case 'book_list_edit':
                if (!isset($message_data['id'])) {
                    Gateway::sendToCurrentClient(self::defaultResponse('内容ID不能为空'));
                }
                $list = BookList::find($message_data['id']);
                if (is_null($list) || $list['server_id'] != $_SESSION['server_id']) {
                    Gateway::sendToCurrentClient(self::defaultResponse('书单不存在'));
                }
                $list->fill($message_data);
                $list->save();
                Gateway::sendToCurrentClient(self::defaultResponse());
                return;

            // 书单删除
            case 'book_list_del':
                if (!isset($message_data['id'])) {
                    Gateway::sendToCurrentClient(self::defaultResponse('内容ID不能为空'));
                }
                $list = BookList::find($message_data['id']);
                if (is_null($list) || $list['server_id'] != $_SESSION['server_id']) {
                    Gateway::sendToCurrentClient(self::defaultResponse('书单不存在'));
                }
                $list->delete();
                Gateway::sendToCurrentClient(self::defaultResponse());
                return;

            // 活动
            case 'activity':
                if (!isset($message_data['user_id'])) {
                    return Gateway::sendToCurrentClient(self::defaultResponse());
                }
                $user = Cache::getDialogByUserId($message_data['user_id']);
                if (!$user || !is_array($user)) {
                    return Gateway::sendToCurrentClient(self::defaultResponse());
                }
                $activities = Activity::whereIn('admin_id', [$user['admin_id'], 0])
                    ->where('status', 1)
                    ->where('start_time', '<', time())
                    ->where('end_time', '>', time())
                    // ->where('name', 'like', '%' . $message_data['activity'] . '%')
                    ->get(['id', 'name', 'is_system', 'recharge', 'gift', 'promotion_text']);

                $activities = $activities->map(function ($item) {
                    $item['name'] = "{$item['name']}-充{$item['recharge']}送{$item['gift']}-{$item['promotion_text']}";
                    return $item;
                });

                Gateway::sendToCurrentClient(self::defaultResponse('', $activities));
                return;
        }
    }

    /**
     * 当客户端断开连接时
     * 清空 business worker 缓存的数据
     * @param integer $client_id 客户端id
     */
    public static function onClose($client_id)
    {
        // debug
        echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id onClose:''\n";

        // 从房间的客户端列表中删除
        if (isset($_SESSION['room_id'])) {
            $room_id = $_SESSION['room_id'];
            $new_message = array('type' => 'logout', 'from_client_id' => $client_id, 'from_client_name' => $_SESSION['client_name'], 'time' => date('Y-m-d H:i:s'));
            Gateway::sendToGroup($room_id, json_encode($new_message));
        }
    }


    public static function defaultResponse($message = 'ok', $data = [], $code = 200)
    {
        return json_encode(
            array(
                'type' => self::$type,
                'message' => $message ?: 'ok',
                'code' => $code,
                'data' => $data,
            )
        );
    }

    public static function resMsg($type, $msg = 'ok~')
    {
        return json_encode(['message' => $msg, 'type' => $type]);
    }
}
